﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Newtonsoft.Json;

namespace Ymatou.ServiceCenter
{
    /// <summary>
    /// 服务依赖配置管理器
    /// </summary>
    public static class ServiceConfigManager
    {
        private static readonly object Locker = new object();
        private static long _updateTime = 0;
        private static readonly SynchronizedDictionary<string, ServiceConfig> ServiceConfigs = new SynchronizedDictionary<string, ServiceConfig>();
        static ServiceConfigManager()
        {
            DaemonThread.Run(AutoUpdateServiceConfig, (ex) => { Logger.Error("AutoUpdateServiceConfigException", ex); }, RpcClientConfigManager.GetServiceMetadataAutoUpdateInterval);
        }

        /// <summary>
        /// 自动同步更新服务依赖配置
        /// </summary>
        static void AutoUpdateServiceConfig()
        {
            FullServiceConfig(Utils.GetConsumerAppId(), _updateTime);

            Logger.Debug("AutoUpdateServiceConfig");
        }

        /// <summary>
        /// 填充服务依赖配置
        /// </summary>
        /// <param name="appId">应用编号</param>
        /// <param name="lastUpdateTicks">最后一次更新时间刻度</param>
        static void FullServiceConfig(string appId, long? lastUpdateTicks = null)
        {
            try
            {
                IList<ServiceConfig> list = null;
                try
                {
                    list = ServiceCenterFacade.GetServiceConfigs(appId, lastUpdateTicks);
                    if (list != null && list.Count > 0)
                        SaveServiceConfigsToLocalConfig(appId, list);

                    StringBuilder sb = new StringBuilder();
                    if (list != null && list.Count > 0)
                    {
                        sb.AppendLine();
                        foreach (ServiceConfig item in list)
                        {
                            if (item == null)
                                continue;
                            sb.AppendLine(item.ToString());
                        }
                    }
                    Logger.Debug(string.Format("AutoUpdateServiceConfig,AppId:{0},LastUpdateTicks:{1},count:{2},items:{3}", appId, lastUpdateTicks, list == null ? 0 : list.Count, sb.ToString()));
                }
                catch (Exception ex)
                {
                    Logger.Error(string.Format("FullServiceConfig:{0},从服务端加载ServiceConfig出现异常！", appId), ex);
                    list = GetServiceConfigFromLocalConfig(appId);
                    Logger.Debug(string.Format("从服务端加载ServiceConfig出现异常，已转为从本地加载！", appId));
                }

                if (list == null || list.Count <= 0)
                    return;
                foreach (ServiceConfig serviceConfig in list)
                {
                    if (serviceConfig == null)
                        continue;
                    string key = string.Format("{0}_{1}", serviceConfig.ConsumerAppId, serviceConfig.ProviderAppId);
                    if (!ServiceConfigs.ContainsKey(key))
                    {
                        ServiceConfigs.Add(key, serviceConfig);
                    }
                    else
                    {
                        ServiceConfigs[key] = serviceConfig;
                    }
                }
                _updateTime = list.OrderByDescending(m => m.LastUpdateTicks).First().LastUpdateTicks;
            }
            catch (Exception ex)
            {
                Logger.Error(string.Format("FullServiceConfig:{0}", appId), ex);
            }
        }

        /// <summary>
        /// 从本地文件中获取服务依赖配置信息
        /// </summary>
        /// <param name="appId">应用编号</param>
        /// <returns></returns>
        private static IList<ServiceConfig> GetServiceConfigFromLocalConfig(string appId)
        {
            string path = Utils.ServiceConfigLocalConfigPath(appId);
            try
            {
                FileInfo fileInfo = new FileInfo(path);
                if (fileInfo.Directory != null && !fileInfo.Directory.Exists)
                {
                    lock (Locker)
                    {
                        if (fileInfo.Directory != null && !fileInfo.Directory.Exists)
                        {
                            fileInfo.Directory.Create();
                            File.WriteAllText(path, "");
                        }
                    }
                }  
                
                string json = File.ReadAllText(path);
                if (string.IsNullOrWhiteSpace(json))
                {
                    Logger.Debug(string.Format("从本地配置文件中没有获取到ServiceConfig信息！{0}", path));
                }
                return JsonConvert.DeserializeObject<List<ServiceConfig>>(json);
            }
            catch (Exception ex)
            {
                Logger.Error(string.Format("从本地配置文件中获取ServiceConfig信息失败！{0}", path), ex);
                return null;
            }
        }

        /// <summary>
        /// 保存服务依赖配置
        /// </summary>
        /// <param name="appId">应用编号</param>
        /// <param name="serviceConfigs">服务依赖配置列表</param>
        private static void SaveServiceConfigsToLocalConfig(string appId, IList<ServiceConfig> serviceConfigs)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(appId) || serviceConfigs == null || serviceConfigs.Count <= 0)
                    return;
                string path = Utils.ServiceConfigLocalConfigPath(appId);
                string json = JsonConvert.SerializeObject(serviceConfigs, Formatting.Indented);

                FileWriter.Write(path, json);
            }
            catch (Exception ex)
            {
                Logger.Error(string.Format("保存元数据配置信息到配置文件:{0}.config中时出现异常！", appId), ex);
            }
        }

        /// <summary>
        /// 获取服务依赖配置
        /// </summary>
        /// <param name="consumerAppId">服务消费者的应用编号</param>
        /// <param name="providerAppId">服务提供者的应用编号</param>
        /// <returns></returns>
        public static ServiceConfig GetServiceConfig(string consumerAppId, string providerAppId)
        {
            if (string.IsNullOrWhiteSpace(consumerAppId))
                throw new ArgumentNullException("consumerAppId");
            if (string.IsNullOrWhiteSpace(providerAppId))
                throw new ArgumentNullException("providerAppId");
            string serviceKey = string.Format("{0}_{1}", consumerAppId, providerAppId);
            return ServiceConfigs.GetWithNoLock(serviceKey);
        }

    }
}
